package database;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import event.Event;

public class EventSerializerPostgreSQL extends EventSerializer {
	private static String DB_DRIVER_DEFAULT = "org.postgresql.Driver";
	private static String DB_CONNECTION_DEFAULT = "jdbc:postgresql://localhost:5432/CEPL";
	private static String DB_USER_DEFAULT = "cepl";
	private static String DB_PASSWORD_DEFAULT = "cepl";

	protected EventSerializerPostgreSQL() throws ClassNotFoundException,
			SQLException {
		if (EventSerializer.DB_CONNECTION == null)
			EventSerializer.DB_CONNECTION = DB_CONNECTION_DEFAULT;
		if (EventSerializer.DB_USER == null)
			EventSerializer.DB_USER = DB_USER_DEFAULT;
		if (EventSerializer.DB_PASSWORD == null)
			EventSerializer.DB_PASSWORD = DB_PASSWORD_DEFAULT;
		if (EventSerializer.DB_DRIVER == null)
			EventSerializer.DB_DRIVER = DB_DRIVER_DEFAULT;

		connect();
	}

	@Override
	public void storeEvent(Event e) {
		try {
			if (teller == 0) {
				String INSERT = "INSERT INTO \"SerializedEvents\" (\"ID\", \"streamID\", \"timestamp\", \"isForwarded\", \"isPrimitive\", \"isCacheable\", \"data\") "
						+ " VALUES (?,?,?,?,?,?,?)";

				for (int i = 1; i < insertBatchSize; ++i) {
					INSERT += ", (?,?,?,?,?,?,?)";
				}

				prepStatement = connection.prepareStatement(INSERT);
			}

			prepStatement.setLong(teller * 7 + 1, e.getID());
			prepStatement.setLong(teller * 7 + 2, e.getStreamID());
			prepStatement.setTimestamp(teller * 7 + 3, e.getTimestamp());
			prepStatement.setBoolean(teller * 7 + 4, e.isForwarded());
			prepStatement.setBoolean(teller * 7 + 5, e.isPrimitive());
			prepStatement.setBoolean(teller * 7 + 6, e.isCacheable());
			prepStatement.setBytes(teller * 7 + 7, e.toSerializedByteArray());

			teller++;
			if (teller == insertBatchSize)
				commitInsertBatch();
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	}

	@Override
	public Event retrieveEvent(long ID) {
		Event result = null;

		try {
			try {
				if (!isConnected())
					connect();
				connection.setAutoCommit(true);
				PreparedStatement ps = connection
						.prepareStatement("SELECT * FROM \"SerializedEvents\" WHERE \"ID\"=?");
				ps.setInt(1, (int) ID);

				ResultSet rs = ps.executeQuery();
				if (rs.next()) {
					byte buf[] = rs.getBytes("data");
					result = new Event(buf);
				}
				rs.close();
				connection.setAutoCommit(false);
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}

		return result;
	}

	@Override
	public long getMaximumSerializedID() {
		long result = 0;
		try {
			try {
				if (!isConnected())
					connect();
				connection.setAutoCommit(true);
				PreparedStatement ps = connection
						.prepareStatement("SELECT MAX(\"ID\") FROM \"SerializedEvents\"");
				ResultSet rs = ps.executeQuery();
				if (rs.next()) {
					int ID = rs.getInt(1);
					result = (long) ID;
				}
				rs.close();
				connection.setAutoCommit(false);
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}

		return result;
	}

	@Override
	public void truncateSerializedEvents() {
		try {
			try {
				if (!isConnected())
					connect();
				connection.setAutoCommit(true);
				Statement stat = connection.createStatement();
				stat.execute("TRUNCATE \"SerializedEvents\"");
				connection.setAutoCommit(false);
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	}

	@Override
	public void createTable() {
		dropTable();

		try {
			try {
				if (!isConnected())
					connect();
				connection.setAutoCommit(true);
				Statement stat = connection.createStatement();
				stat.executeUpdate("CREATE TABLE \"SerializedEvents\"("
						+ "\"ID\" bigint NOT NULL," + "\"streamID\" bigint,"
						+ "\"timestamp\" timestamp without time zone NOT NULL,"
						+ "\"isForwarded\" boolean NOT NULL,"
						+ "\"isPrimitive\" boolean NOT NULL,"
						+ "\"isCacheable\" boolean NOT NULL,"
						+ "\"data\" bytea NOT NULL)");

				connection.setAutoCommit(false);
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	}

	@Override
	public void dropTable() {
		try {
			try {
				if (!isConnected())
					connect();
				connection.setAutoCommit(true);
				Statement stat = connection.createStatement();
				stat.executeUpdate("DROP TABLE IF EXISTS \"SerializedEvents\"");

				connection.setAutoCommit(false);
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	}
}
